package com.rpg.world;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;

import com.rpg.Drawable_I;
import com.rpg.R;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;

enum PlotDir {NORTH, SOUTH, EAST, WEST};

public class Plot implements Drawable_I {
	
	public Plot(int x, int y, int c, int t, Resources res, int pct, int duns, View view) {
		this.x = x;
		this.y = y;
		this.mapKey = x + "," + y;
		this.trees = new Sprite[t];
		for(int i = 0; i < t; i++) {
			this.trees[i] = new Sprite(
					BitmapFactory.decodeResource(res, R.drawable.tree), 
					rand.nextInt(MAX_DIM), rand.nextInt(MAX_DIM));
		}
		this.backColor = c;
		this.attackChance = pct;

		for(int i = 0; i < duns; i++) {
			this.dungeons.add(
					new Sprite(
							BitmapFactory.decodeResource(res, R.drawable.sm_cutlasses), 
							rand.nextInt(MAX_DIM), rand.nextInt(MAX_DIM)));
		}
		mountain = BitmapFactory.decodeResource(res, R.drawable.sm_mountain);
	}
	
	public Bitmap makeStaticImage(int w, int h) {
		Bitmap bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
		Canvas c = new Canvas(bmp);
		c.drawColor(backColor);
		if (!hasPlotToThe(PlotDir.NORTH)) {
			int maxW = w;
			for (int x = 0; x < maxW; x += 30) {
				c.drawBitmap(mountain, x - 14 + rand.nextInt(14), -4 + rand.nextInt(10), myP);
			}
		}
		if (!hasPlotToThe(PlotDir.SOUTH)) {
			int myH = h - 20;
			int maxW = w;
			for (int x = 0; x < maxW; x += 30) {
				c.drawBitmap(mountain, x - 14 + rand.nextInt(14), myH - 8 + rand.nextInt(10), myP);
			}
		}
		if (!hasPlotToThe(PlotDir.WEST)) {
			int maxH = h;
			for (int y = 0; y < maxH; y += 20) {
				c.drawBitmap(mountain, -25 + rand.nextInt(14), y, myP);
			}
		}
		if (!hasPlotToThe(PlotDir.EAST)) {
			int myH = w - 30;
			int maxH = h;
			for (int y = 0; y < maxH; y += 20) {
				c.drawBitmap(mountain, myH + 14 - rand.nextInt(14), y, myP);
			}
		}
		for(Sprite tree : trees) {
			tree.onDraw(c);
		}
		for(Sprite d : dungeons) {
			d.onDraw(c);
		}
		return bmp;
	}

	public void onDraw(Canvas canvas) {
		canvas.drawBitmap(myBitmap, 0, 0, myP);
	}
	
	public boolean hitDungeon(Sprite guy) {
		for(Sprite s : dungeons) {
			if (s.overlaps(guy)) {
				return true;
			}
		}
		return false; 
	}

	public boolean hasPlotToThe(PlotDir dir) {
		switch(dir) {
		case NORTH:
			return AllPlots.containsKey(x + "," + (y - 1)); 
		case SOUTH:
			return AllPlots.containsKey(x + "," + (y + 1)); 
		case WEST:
			return AllPlots.containsKey((x - 1) + "," + y); 
		case EAST:
			return AllPlots.containsKey((x + 1) + "," + y);
		default:
			return false;
		}
	}
	
	public Plot getNeighbor(PlotDir dir) {
		switch(dir) {
		case NORTH:
			return AllPlots.get(x + "," + (y - 1)); 
		case SOUTH:
			return AllPlots.get(x + "," + (y + 1)); 
		case WEST:
			return AllPlots.get((x - 1) + "," + y); 
		case EAST:
			return AllPlots.get((x + 1) + "," + y);
		default:
			return null;
		}
	}
	
	public static void readPlots(InputStream in, Resources res, View view) {
		try {
			BufferedReader reader = new BufferedReader (new InputStreamReader(in), 512);
			try {
				while (true) {
					Plot p = read(reader, res, view);
					AllPlots.put(p.mapKey, p);
				}
			}
			catch (NullPointerException npe) {
				// Log.d("Plot", npe.getMessage());
			}
			for(Map.Entry<String, Plot> entry : AllPlots.entrySet()) {
				Plot p = entry.getValue();
				p.myBitmap = p.makeStaticImage(view.getWidth(), view.getHeight());
			}
		}
		catch (IOException exn) {
			Log.e("Plot", exn.getMessage());
		}
	}
	
	public static Plot getStartPlot() {
		return AllPlots.get("0,0");
	}

	private static Plot read(BufferedReader in, Resources res, View view) throws IOException {
		// String plotLiteral = 
		expect("plot:", ignoreEmptyAndComments(in));
		int x = expectInt("x:", ignoreEmptyAndComments(in));
		int y = expectInt("y:", ignoreEmptyAndComments(in));
		String color = expect("color:", ignoreEmptyAndComments(in));
		int trees = expectInt("trees:", ignoreEmptyAndComments(in));
		int pct = expectInt("attack_pct:", ignoreEmptyAndComments(in));
		int duns = expectInt("dungeons:", ignoreEmptyAndComments(in));
		return new Plot(x, y, Color.parseColor(color), trees, res, pct, duns, view);
	}
	
 	static private String ignoreEmptyAndComments(BufferedReader in) throws IOException {
		String s = in.readLine().trim();
		while (s.equals("") || s.startsWith("#")) {
			s = in.readLine().trim();
		}
		return s;
	}
	
	static private int expectInt(String label, String input) {
		return Integer.parseInt(expect(label, input));
	}
	
	static private String expect(String label, String input) {
		if (!input.startsWith(label)) {
			throw new IllegalArgumentException(input);
		}
		return input.substring(label.length()).trim();
	}

	final int x, y, backColor, attackChance;
	private Bitmap myBitmap;

	final Sprite[] trees;
	final String mapKey;
	final private HashSet<Sprite> dungeons = new HashSet<Sprite> ();
	final private Bitmap mountain;

	static Random rand = new Random();
	static final private Paint myP = new Paint();
	static final int MAX_DIM = 200;
	static final Map<String, Plot> AllPlots = new HashMap<String, Plot>();
}
